class Vue{
    constructor(options){
        this.$el = options.el;
        this.$data = options.data;

        if(this.$el){
            //数据劫持
            new Observer(this.$data);
            //把数据和模板进行编译
            new Complie(this.$el,this);
        }
    }
}

class Observer{
    constructor(data){
        this.observer(data);
    }

    observer(data){
        if(data && typeof data === 'object'){
            for(let key in data){
                this.observerData(data,key,data[key]);
            }
        }
    }

    observerData(data,key,value){
        this.observer(value);
        Object.defineProperty(data,key,{
            set(newVal){
                if(value != newVal){
                    value = newValue
                }
            },
            get(){
                return value
            }
        })
    }
}

class Complie{
    constructor(el,vm){
        this.vm = vm;
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        
        let fragment = this.nodeToFragment(this.el);

        this.compile(fragment);

        this.el.appendChild(fragment);
    }

    isDirective(attr){
        return  attr.startsWith('v-');
    }

    compileElement(node){
        let attrs = node.attributes;
        [...attrs].forEach(attr => {
            let {name,value:expr} = attr;
            if(this.isDirective(name)){
                let [,directive] = name.split('-');
                compileUtil[directive](node,expr,this.vm);
            }
        })
        console.log(attrs)
    }

    compileText(node){
        let content = node.textContent;
        if(/\{\{(.+?)\}\}/.test(content)){
            compileUtil.content(node,content,this.vm);
        }
    }

    compile(node){
        let childnodes = node.childNodes;
        [...childnodes].forEach(child => {
            if(this.isElementNode(child)){
                //元素
                this.compileElement(child);
                this.compile(child);
            }else{
                //文本
                this.compileText(child)
            }
        })
    }

    nodeToFragment(node){
        let fragment = document.createDocumentFragment();

        let firstChild;

        while(firstChild = node.firstChild){
            fragment.appendChild(firstChild);
        }
        return fragment
    }

    isElementNode(node){
        return node.nodeType === 1
    }
}

compileUtil = {
    getVal(expr,vm){
        return expr.split('.').reduce((pre,cur) => {
            return pre[cur]
        },vm.$data)
    },
    model(node,expr,vm){
        let val = this.getVal(expr,vm);

        let fn = this.updater.compileModel;

        fn(node,val);
    },
    content(node,content,vm){
        let value = content.replace(/\{\{(.+?)\}\}/g,(...expr) => {
            return this.getVal(expr[1],vm);
        })
        console.log(value)
        let fn = this.updater.compileContent;

        fn(node,value);
    },
    text(){

    },
    updater:{
        compileModel(node,value){
            node.value = value;
        },
        compileContent(node,value){
            node.textContent = value;
        }
    }
}